from info.models import Mail, MailReceive
from department.models import Department
from project.models import Project
from user.models import User
from django.db import transaction
from department.utils import assert_department_permissions
from department.utils.member import assert_member_of as assert_department_member_of
from project.utils.permission import assert_project_permissions
from project.utils.member import assert_member_of as assert_project_member_of
from user.utils.permission import assert_system_permissions
from pms.common.views import PermissionDeny
from pms.common.utils import flatten_view


class InvalidRecipient(Exception):
    def __init__(self, user):
        Exception.__init__(self)
        self.user = user


@transaction.atomic
def create_mail(user, title, content, recipients, department=None, project=None):
    assert isinstance(user, User)
    assert department is None or isinstance(department, Department)
    assert project is None or isinstance(project, Project)
    # 创建邮件
    if department is not None:  # 系统邮件
        assert_department_member_of(user, department)
        assert_department_permissions(user.id, department.id, [4])
        mail = Mail(title=title, content=content, uid=user, did=department, pid=None)
    elif project is not None:  # 项目邮件
        assert_project_member_of(user, project)
        assert_project_permissions(project.id, user.id, [6])
        mail = Mail(title=title, content=content, uid=user, did=None, pid=project)
    else:  # 系统邮件
        assert_system_permissions(user.id, [15])
        mail = Mail(title=title, content=content, uid=user, did=None, pid=None)
    mail.save()
    # 创建收件关系
    for recipient in recipients:
        user = User.objects.get(id=recipient['id'])
        try:
            if department is not None:
                assert_department_member_of(user, department)
            elif project is not None:
                assert_project_member_of(user, project)
        except PermissionDeny:
            raise InvalidRecipient(user)
        receive = MailReceive(mid=mail, uid=user)
        receive.save()
    return mail


@transaction.atomic
def update_mail(mail, view):
    assert isinstance(mail, Mail)
    argv = flatten_view(view, {
        'title': 'title',
        'content': 'content'
    })
    mail.__dict__.update(**argv)
    mail.save()
    # update recipients
    if 'recipients' in view and view['recipients'] is not None:
        target_recipients = set([int(r['id']) for r in view['recipients']])
        current_recipients = set(MailReceive.objects.filter(mid=mail).values_list('uid_id', flat=True))
        more_recipients = current_recipients - target_recipients
        less_recipients = target_recipients - current_recipients
        for r in more_recipients:
            receive = MailReceive.objects.get(mid=mail, uid_id=r)
            receive.delete()
        for r in less_recipients:
            user = User.objects.get(id=r)
            try:
                if mail.did is not None:
                    assert_department_member_of(user, mail.did)
                elif mail.pid is not None:
                    assert_project_member_of(user, mail.pid)
            except PermissionDeny:
                raise InvalidRecipient(user)
            MailReceive(mid=mail, uid=user).save()
    return mail
